package com.market.util;

import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

public class DataConnection {
	static public DataConnection instance;
	static public int clients;
	public Vector drivers = new Vector();
	public PrintWriter log;
	public Hashtable pools = new Hashtable();

	static synchronized public DataConnection getInstance() {
		if (instance == null) {
			instance = new DataConnection();
		}
		clients++;
		return instance;
	}

	/**
	 * 建构函数私有以防止其它对象创建本类实�?
	 */
	public DataConnection() {
		init();
	}

	public void freeConnection(String name, Connection con) {
		DBConnectionPool pool = (DBConnectionPool) pools.get(name);
		if (pool != null) {
			pool.freeConnection(con);
		} else {
			System.out.println("pool ==null");
		}
		clients--;
	}

	/**
	 * 获得�?��可用�?空闲�?连接.如果没有可用连接,且已有连接数小于�?��连接�?限制,则创建并返回新连�?
	 * 
	 * @param name
	 *            在属性文件中定义的连接池名字
	 * @return Connection 可用连接或null
	 */
	public Connection getConnection(String name) {
		DBConnectionPool pool = (DBConnectionPool) pools.get(name);
		if (pool != null) {
			// return pool.getConnection();
			return pool.returnConnection();
		}
		return null;
	}

	/**
	 * 获得�?��可用连接.若没有可用连�?且已有连接数小于�?��连接数限�? 则创建并返回新连�?否则,在指定的时间内等待其它线程释放连�?
	 * 
	 * @param name
	 *            连接池名�?
	 * @param time
	 *            以毫秒计的等待时�?
	 * @return Connection 可用连接或null
	 */
	public Connection getConnection(String name, long time) {
		DBConnectionPool pool = (DBConnectionPool) pools.get(name);
		if (pool != null) {
			return pool.getConnection(time);
		}
		return null;
	}

	/**
	 * 关闭�?��连接,撤销驱动程序的注�?
	 */
	public synchronized void release() {
		// 等待直到�?���?��客户程序调用
		if (--clients != 0) {
			return;
		}
		Enumeration allPools = pools.elements();
		while (allPools.hasMoreElements()) {
			DBConnectionPool pool = (DBConnectionPool) allPools.nextElement();
			pool.release();
		}
		Enumeration allDrivers = drivers.elements();
		while (allDrivers.hasMoreElements()) {
			Driver driver = (Driver) allDrivers.nextElement();
			try {
				DriverManager.deregisterDriver(driver);
				System.out.println("撤销JDBC驱动程序 " + driver.getClass().getName());
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 根据指定属�?创建连接池实�?
	 * 
	 * @param props
	 *            连接池属�?
	 */
	private void createPools(Map<String, String> props) {
		String poolName = props.get("poolName");
		String url = props.get("url");
		String user = props.get("username");
		String password = props.get("password");
		int max = Integer.valueOf(props.get("max")).intValue();

		DBConnectionPool pool = new DBConnectionPool(poolName, url, user,
				password, max);
		pools.put(poolName, pool);
		System.out.println("成功创建连接�?" + poolName);
	}

	/**
	 * 读取属�?完成初始�?
	 */
	private void init() {
		Utils ut = new Utils();
		Map<String, String> map = ut.readXml();
		loadDrivers(map);
		createPools(map);
	}

	/**
	 * 171 * 装载和注册所有JDBC驱动程序 172 * 173 * @param props 属�? 174
	 */
	private void loadDrivers(Map<String,String> props) {
		String driverClasses = props.get("drivers");
		System.out.println(driverClasses);
		StringTokenizer st = new StringTokenizer(driverClasses);
		while (st.hasMoreElements()) {
			String driverClassName = st.nextToken().trim();
			try {
				Driver driver = (Driver) Class.forName(driverClassName)
						.newInstance();
				DriverManager.registerDriver(driver);
				drivers.addElement(driver);
				System.out.println(driverClassName);
				System.out.println("成功注册JDBC驱动程序" + driverClassName);
			} catch (Exception e) {
				System.out.println("无法注册JDBC驱动程序: " + driverClassName + ", 错误: " + e);
			}
		}
	}


	/**
	 * 此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最 大连接数为止.在返回连接给客户程序之前,它能够验证连接的有效�?
	 */
	class DBConnectionPool {
		private Vector freeConnections = new Vector();
		private int maxConn;
		private String name;
		private String password;
		private String URL;
		private String user;

		/**
		 * 创建新的连接�?
		 * 
		 * @param name
		 *            连接池名�?
		 * @param URL
		 *            数据库的JDBC URL
		 * @param user
		 *            数据库帐�?�?null
		 * @param password
		 *            密码,�?null
		 * @param maxConn
		 *            此连接池允许建立的最大连接数
		 */
		public DBConnectionPool(String name, String URL, String user,
				String password, int maxConn) {
			this.name = name;
			this.URL = URL;
			this.user = user;
			this.password = password;
			this.maxConn = maxConn;
		}

		/**
		 * 将不再使用的连接返回给连接池
		 * 
		 * @param con
		 *            客户程序释放的连�?
		 */
		public synchronized void freeConnection(Connection con) {
			// 将指定连接加入到向量末尾
			try {
				if (con.isClosed()) {
					System.out.println("before freeConnection con is closed");
				}
				freeConnections.addElement(con);
				Connection contest = (Connection) freeConnections.lastElement();
				if (contest.isClosed()) {
					System.out
							.println("after freeConnection contest is closed");
				}
				notifyAll();
			} catch (SQLException e) {
				System.out.println(e);
			}
		}

		/**
		 * 从连接池获得�?��可用连接.如没有空闲的连接且当前连接数小于�?��连接 数限�?则创建新连接.如原来登记为可用的连接不再有�?则从向量删除�?
		 * 然后递归调用自己以尝试新的可用连�?
		 */
		public synchronized Connection getConnection() {
			Connection con = null;
			if (freeConnections.size() > 0) {
				// 获取向量中第�?��可用连接
				con = (Connection) freeConnections.firstElement();
				freeConnections.removeElementAt(0);
				try {
					if (con.isClosed()) {
						System.out.println("从连接池" + name + "删除�?��无效连接");
						System.out.println("从连接池" + name + "删除�?��无效连接");
						// 递归调用自己,尝试再次获取可用连接
						con = getConnection();
					}
				} catch (SQLException e) {
					System.out.println("从连接池" + name + "删除�?��无效连接时错�?");
					System.out.println("从连接池" + name + "删除�?��无效连接出错");
					// 递归调用自己,尝试再次获取可用连接
					con = getConnection();
				}
				if (freeConnections.size() > maxConn) {
					System.out.println(" 删除�?��溢出连接 ");
					releaseOne();
				}
			} else if ((maxConn == 0) || (freeConnections.size() < maxConn)) {
				con = newConnection();
			}
			return con;
		}

		public synchronized Connection returnConnection() {
			Connection con = null;
			// 如果闲置小于�?��连接,返回�?��新连�?
			if (freeConnections.size() < maxConn) {
				con = newConnection();
			}
			// 如果闲置大于�?��连接，返回一个可用的旧连�?
			else if (freeConnections.size() >= maxConn) {
				con = (Connection) freeConnections.firstElement();
				System.out.println(" [a 连接池可用连接数 ] : " + "[ "
						+ freeConnections.size() + " ]");
				freeConnections.removeElementAt(0);
				System.out.println(" [b 连接池可用连接数 ] : " + "[ "
						+ freeConnections.size() + " ]");
				try {
					if (con.isClosed()) {
						System.out.println("从连接池" + name + "删除�?��无效连接");
						System.out.println("从连接池" + name + "删除�?��无效连接");
						returnConnection();
					}
				} catch (SQLException e) {
					System.out.println("从连接池" + name + "删除�?��无效连接时错�?");
					System.out.println("从连接池" + name + "删除�?��无效连接出错");
					returnConnection();
				}
			}
			return con;
		}

		/**
		 * 从连接池获取可用连接.可以指定客户程序能够等待的最长时�?参见前一个getConnection()方法.
		 * 
		 * @param timeout
		 *            以毫秒计的等待时间限�?
		 */
		public synchronized Connection getConnection(long timeout) {
			long startTime = new Date().getTime();
			Connection con;
			while ((con = getConnection()) == null) {
				try {
					wait(timeout);
				} catch (InterruptedException e) {
				}
				if ((new Date().getTime() - startTime) >= timeout) {
					// wait()返回的原因是超时
					return null;
				}
			}
			return con;
		}

		/**
		 * 关闭�?��连接
		 */
		public synchronized void release() {
			Enumeration allConnections = freeConnections.elements();
			while (allConnections.hasMoreElements()) {
				Connection con = (Connection) allConnections.nextElement();
				try {
					con.close();
					System.out.println("关闭连接�?" + name + "中的�?��连接");
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			freeConnections.removeAllElements();
		}

		/**
		 * 关闭�?��连接
		 */
		public synchronized void releaseOne() {
			if (freeConnections.firstElement() != null) {
				Connection con = (Connection) freeConnections.firstElement();
				try {
					con.close();
					System.out.println("关闭连接�?" + name + "中的�?��连接");
					//log("关闭连接�? + name + "中的�?��连接");
				} catch (SQLException e) {
					e.printStackTrace();
				}
			} else {
				System.out
						.println("releaseOne() bug.......................................................");
			}
		}

		/**
		 * 创建新的连接
		 */
		private Connection newConnection() {
			Connection con = null;
			try {
				if (user == null) {
					con = DriverManager.getConnection(URL);
				} else {
					con = DriverManager.getConnection(URL, user, password);
				}
				System.out.println("连接�?" + name + "创建�?��新的连接");
			} catch (SQLException e) {
				e.printStackTrace();
				return null;
			}
			return con;
		}
	}
}
